#include "CUKeyUValueCalc.h"
#include "CLogRecord.h"
#include "CTableConfigure.h"
#include <boost/crc.hpp>
#include <sstream>
#include <iostream>

CUKeyUValueCalc::CUKeyUValueCalc(CTableBase* tablePtr)
	: m_tablePtr(tablePtr), m_uKey(0), m_uValue(0)
{
}

void CUKeyUValueCalc::CalculateUKeyUValue(const CLogRecordPtr& logRecord)
{
	try {
		// Get table configuration
		CTableConfigurePtr tableConfigure = m_tablePtr->getTableConfigure();
		if (!tableConfigure || !logRecord) {
			return;
		}
		
		// Get key fields and value fields from configuration
		auto keyFields = tableConfigure->getKeyFields();
		auto valueFields = tableConfigure->getValueFields();
		
		// Get record fields
		auto& recordFields = logRecord->GetFields();
		
		// Calculate uKey from key fields
		m_uKey = CalculateCRC32FromFields(keyFields, recordFields, "uKey");
		
		// Calculate uValue from value fields
		m_uValue = CalculateCRC32FromFields(valueFields, recordFields, "uValue");
		
	} catch (const std::exception& e) {
		std::cout << "Error in CalculateUKeyUValue: " << e.what() << std::endl;
	}
}

uint64_t CUKeyUValueCalc::CalculateCRC32FromFields(const std::vector<std::string>& fieldNames, 
                                                   const std::map<std::string, CLogFieldPtr>& recordFields,
                                                   const std::string& fieldType)
{
	// Build concatenated string from field values
	std::stringstream concatenatedValues;
	bool firstField = true;
	
	for (const auto& fieldName : fieldNames) {
		// Find the field in the record
		auto it = recordFields.find(fieldName);
		if (it != recordFields.end()) {
			CLogFieldPtr field = it->second;
			const CLogValue& value = field->GetValue();
			
			// Add separator if not the first field
			if (!firstField) {
				concatenatedValues << "|";
			}
			firstField = false;
			
			// Convert value to string based on type
			if (value.type() == typeid(uint64_t)) {
				concatenatedValues << boost::get<uint64_t>(value);
			} else if (value.type() == typeid(double)) {
				concatenatedValues << boost::get<double>(value);
			} else if (value.type() == typeid(std::string)) {
				concatenatedValues << boost::get<std::string>(value);
			} else {
				// Unknown type, add empty string
				concatenatedValues << "";
			}
		} else {
			// Field not found, add empty string but still add separator
			if (!firstField) {
				concatenatedValues << "|";
			}
			firstField = false;
			concatenatedValues << "";
		}
	}
	
	// Get the concatenated string
	std::string concatenatedString = concatenatedValues.str();
	
	// Calculate CRC32 using Boost
	boost::crc_32_type crc32;
	crc32.process_bytes(concatenatedString.c_str(), concatenatedString.length());
	
	// Debug output
	std::cout << fieldType << " fields: ";
	for (size_t i = 0; i < fieldNames.size(); ++i) {
		if (i > 0) std::cout << ", ";
		std::cout << fieldNames[i];
	}
	std::cout << std::endl;
	std::cout << fieldType << " concatenated string: '" << concatenatedString << "'" << std::endl;
	std::cout << fieldType << " CRC32: 0x" << std::hex << crc32.checksum() << std::dec << std::endl;
	
	return static_cast<uint64_t>(crc32.checksum());
}

uint64_t CUKeyUValueCalc::getUKey() const
{
	return m_uKey;
}

uint64_t CUKeyUValueCalc::getUValue() const
{
	return m_uValue;
}

